/****************************************************************************
*					ImprovedGreedyAlgorithm
*
*	Description:	Improved greedy algorithm for structure learning of PGM
*
****************************************************************************/

#ifndef _ImprovedGreedyAlgorithm_H
#define _ImprovedGreedyAlgorithm_H

#include <vector>
#include <math.h>
#include "PGMStruct.h"
#include "DataSet.h"
#include "StructureLearning.h"
#include "ParameterLearning.h"
#include "ParameterLearningFactory.h"
#include "Inference.h"
#include "InferenceFactory.h"

class ImprovedGreedyAlgorithm : public StructureLearning {
  private:

  protected:

	  

	  // Algorithm for optimizing parameters of the PGM
	ParameterLearning* parameterLearning;

	  // Algorithm for running inference
	Inference* inference;

	  /* FUNCTIONS */
	  // Function to calculate gain in likelihood given EP value and EQ value for a feature
	static inline double likelihoodGain (const double& empiricalProb, const double& mrfProb) {
		return pow((empiricalProb / mrfProb), empiricalProb) * pow ((1 - empiricalProb) / (1 - mrfProb), 1 - empiricalProb); }
	static inline float likelihoodGain (const float& empiricalProb, const float& mrfProb) {
		return pow((empiricalProb / mrfProb), empiricalProb) * pow ((1 - empiricalProb) / (1 - mrfProb), 1 - empiricalProb); }

	// Function sets new feature weight given its emprical probability and expected value w.r.t. current state of PGM
	static inline double weightValue (const double& empiricalProb, const double& mrfProb) {
		return (double) log ((empiricalProb / (1 - empiricalProb)) * ((1 - mrfProb)  / mrfProb)); }
	static inline float weightValue (const float& empiricalProb, const float& mrfProb) {
		return (float) log ((empiricalProb / (1 - empiricalProb)) * ((1 - mrfProb)  / mrfProb)); }

	  // Returns a set of features with high empirical probability
	int getFeatsHighEP (std::vector <std::vector < std::pair<unsigned int, unsigned int> > >& newFeats, DataSet& dataSet);

	  // Returns a set of features that have high expected value w.r.t. PGM; The result vector can contain repeats
	int getFeatsHighEQ (std::vector <std::vector < std::pair<unsigned int, unsigned int> > >& newFeats, unsigned int& newFeatsSize,
		std::vector <unsigned int>& newFeatsSizes, const unsigned int& maxFeatSize, std::vector < std::pair<unsigned int, unsigned int> >& lastAddedFeature, PGMStruct& pgmStruct) const;

	  // Combines individual features in order to get a set of features with high EP
	int combineFeatures (const unsigned int& step, std::vector <std::vector <unsigned int> >& indivFeats, std::vector <std::vector < std::pair<unsigned int, unsigned int> > >& feats, DataSet& dataSet) const;

  public:
// TEMPORARY ALL DATA IS IN PUBLIC - for parameter optimizing purposes only
	  /* DATA */
	  // Current value of threshold - used in combineFeatures function
	unsigned int threshold;
	  // threshold for EP values of individual features (for them to be considered)
	double thresholdForIndividualFeats;
	  // threshold for EP values of arbitrary features (for them to be used in the algorithm
	double thresholdForArbitraryFeats;
	  // min number of individual features from one variable
	unsigned int minNumOfIndivFeatsPerVariable;
	  // max size of arbitrary features (for them to be used in the algorithm)
	unsigned int maxSizeOfArbitraryFeats;
	  // max number of features with high EQ and low EP to be added at each step of the greedy algorithm
	unsigned int maxNumOfFeatsHighEQAdded;
	  // max number of all featues in the PGM
	unsigned int maxWholeNumOfFeats;
	  // min acceptable gain in likelihood to continue adding features with high EP
	double minLikelihoodGainHighEP;
	  // min acceptable gain in likelihood to continue adding features with high EQ
	double minLikelihoodGainHighEQ;
	  // stopping criteria: if the we get same objective function value for thin number of iterations - than stop
	unsigned int numIterWithSameValue;
// END OF TEMPORARY THING

	  // Standard constructor
	ImprovedGreedyAlgorithm(void);
      
	  // Standard destructor
    ~ImprovedGreedyAlgorithm();

      // Calculating feature value
	int learn (DataSet& dataSetLearn, PGMStruct& pgmStruct);

	  // Set object patameters from environment
	int setParameters (Environment &environment);

}; // end of class

#endif // _ImprovedGreedyAlgorithm_H
